home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / accounts / adduser.000 / adduser / adduser.shadow.1.5 / adduser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-10  |  12.2 KB  |  429 lines

  1. /****
  2. ** 5/26/96
  3. ** shadow-adduser 1.5:
  4. **
  5. ** Just made it ask for your password twice.
  6. **
  7. ** David L Robinson
  8. ** drobinso@nrg.com.au
  9. **
  10. ** 6/27/95
  11. ** shadow-adduser 1.4:
  12. **
  13. ** now it copies the /etc/skel dir into the person's dir, 
  14. ** makes the mail folders, changed some defaults and made a 'make 
  15. ** install' just for the hell of it.
  16. **
  17. ** Greg Gallagher
  18. ** CIN.Net
  19. **
  20. ** 1/28/95
  21. ** shadow-adduser 1.3:
  22. ** 
  23. ** Basically a bug-fix on my additions in 1.2.  Thanx to Terry Stewart 
  24. ** (stew@texas.net) for pointing out one of the many idiotic bugs I introduced.
  25. ** It was such a stupid bug that I would have never seen it myself.
  26. **
  27. **                                Brandon
  28. *****
  29. ** 01/27/95
  30. ** 
  31. ** shadow-adduser 1.2:
  32. ** I took the C source from adduser-shadow (credits are below) and made
  33. ** it a little more worthwhile.  Many small changes... Here's
  34. ** the ones I can remember:
  35. ** 
  36. ** Removed support for non-shadowed systems (if you don't have shadow,
  37. **     use the original adduser, don't get this shadow version!)
  38. ** Added support for the correct /etc/shadow fields (Min days before
  39. **     password change, max days before password change, Warning days,
  40. **     and how many days from expiry date does the account go invalid)
  41. **     The previous version just left all of those fields blank.
  42. **     There is still one field left (expiry date for the account, period)
  43. **     which I have left blank because I do not use it and didn't want to
  44. **     spend any more time on this.  I'm sure someone will put it in and
  45. **     tack another plethora of credits on here. :)
  46. ** Added in the password date field, which should always reflect the last
  47. **     date the password was changed, for expiry purposes.  "passwd" always
  48. **     updates this field, so the adduser program should set it up right
  49. **     initially (or a user could keep thier initial password forever ;)
  50. **     The number is in days since Jan 1st, 1970.
  51. **
  52. **                       Have fun with it, and someone please make
  53. **                       a real version(this is still just a hack)
  54. **                       for us all to use (and Email it to me???)
  55. **
  56. **                               Brandon
  57. **                                  photon@usis.com
  58. **
  59. ***** 
  60. ** adduser 1.0: add a new user account (For systems not using shadow)
  61. ** With a nice little interface and a will to do all the work for you.
  62. **
  63. ** Craig Hagan
  64. ** hagan@opine.cs.umass.edu
  65. **
  66. ** Modified to really work, look clean, and find unused uid by Chris Cappuccio
  67. ** chris@slinky.cs.umass.edu
  68. **
  69. *****
  70. **
  71. ** 01/19/95
  72. **
  73. ** FURTHER modifications to enable shadow passwd support (kludged, but
  74. ** no more so than the original)  by Dan Crowson - dcrowson@mo.net
  75. **
  76. ** Search on DAN for all changes...
  77. **
  78. *****
  79. **
  80. ** cc -O -o adduser adduser.c
  81. ** Use gcc if you have it... (political reasons beyond my control) (chris)
  82. **
  83. ** I've gotten this program to work with success under Linux (without
  84. ** shadow) and SunOS 4.1.3. I would assume it should work pretty well
  85. ** on any system that uses no shadow. (chris)
  86. **
  87. ** If you have no crypt() then try
  88. ** cc -DNO_CRYPT -O -o adduser adduser.c xfdes.c
  89. ** I'm not sure how login operates with no crypt()... I guess
  90. ** the same way we're doing it here.
  91. */
  92.  
  93. #include <pwd.h>
  94. #include <grp.h>
  95. #include <ctype.h>
  96. #include <stdio.h>
  97. #include <string.h>
  98. #include <unistd.h>
  99. #include <time.h>
  100. #include <sys/types.h>
  101. #include <sys/timeb.h>
  102. #include <sys/time.h>
  103. #include <sys/stat.h>
  104.  
  105. #define PASSWD_FILE    "/etc/passwd"
  106.  
  107. #define SHADOW_FILE    "/etc/shadow"
  108.  
  109. #define DEFAULT_SHELL    "/bin/bash"  /* because BASH is your friend */
  110. #define DEFAULT_HOME    "/home"
  111.  
  112. #define DEFAULT_GROUP    100
  113.  
  114. #define FIRST        500
  115.  
  116. #define DEFAULT_PERMS    0700    /* Perms for the users home directory */
  117.  
  118. #define DEFAULT_MIN_PASS 0
  119. #define DEFAULT_MAX_PASS 30
  120. #define DEFAULT_WARN_PASS 15
  121. #define DEFAULT_USER_DIE 10
  122.  
  123. int unused_uid,nag;
  124. char *crypt();
  125.  
  126. main()
  127. {
  128.   char foo[32];            
  129.  
  130.   char uname[9],person[32],dir[32],shell[32],salt[2];
  131.  
  132.   char *passwd;
  133.   
  134.   char *passwdone;
  135.   
  136.   char *passwdtwo;
  137.  
  138.   char tmp[255];
  139.  
  140.   char commandbuf[80];
  141.  
  142.   char cogusbuf[12];
  143.   
  144.   char *strd(char *s) {
  145.       char *d;
  146.       d=(char *)malloc(strlen(s) + 1);
  147.       strcpy(d,s);
  148.       return(d);
  149.       }
  150.  
  151.  
  152.   unsigned int group,uid,pass_change_date,min_pass,max_pass,warn_pass,user_die;
  153.  
  154.   /* the group and uid of the new user */
  155.  
  156.   int bad=0,done=0,correct=0,gets_warning=0,perfect=0;
  157.  
  158.   /* flags, in order:
  159.    * bad to see if the username is in /etc/passwd, or if strange stuff has
  160.    * been typed if the user might be put in group 0
  161.    * done allows the program to exit when a user has been added
  162.    * correct loops until a password is found that isn't in /etc/passwd
  163.    * gets_warning allows the fflush to be skipped for the first gets
  164.    * so that output is still legible
  165.    */
  166.  
  167.   time_t tm;
  168.  
  169.   struct passwd *pw;
  170.  
  171.   FILE *passwd_file;  /* Yep, it's a file allright */
  172.  
  173.   FILE *shadow_file;
  174.   
  175.   /* set unused uid to FIRST (#defined above) so that find_unused picks
  176.    * a uid over FIRST (assuming we do everything else right :)
  177.    */
  178.  
  179.   unused_uid = FIRST;
  180.  
  181.   /* The real program starts HERE! */
  182.  
  183.   /* Smile, it's the 2nd best thing you can do with your lips */
  184.  
  185.   /* Lesse if we know what we're doing here... */
  186.   
  187.   if(geteuid()!=0)
  188.   {
  189.      printf("It seems you don't have access to add a new user.  Try\n");
  190.      printf("logging in as root or su root to gain super-user access.\n");
  191.      exit(1);
  192.   }
  193.   
  194.   /* We don't support shadow password files, let's check and make
  195.    * sure we're not using em. Sure we could use filesearch or something
  196.    * but i don't feel like it.
  197.    */
  198.  
  199.   while(!correct)        /* loop until a "good" uname is chosen */
  200.     {                /* good = not in /etc/passwd */
  201.       while(!done)
  202.     {
  203.       printf("\nUser to add (^C to quit): ");
  204.  
  205.       if(gets_warning)    /* if the warning was already shown */
  206.         fflush(stdout);    /* fflush stdout, otherwise set the flag */
  207.       else
  208.         gets_warning=1;
  209.  
  210.       gets(uname);
  211.  
  212.           /* what I saw here before made me think maybe I was running DOS */
  213.           /* might this be a solution? (chris) */
  214.       if(nag=getpwnam(uname) != NULL)
  215.         {
  216.           printf("That name is in use, choose another.\n");
  217.           done=0;
  218.         }
  219.       else done=1;
  220.     }
  221.  
  222.       /* all set, get the rest of the stuff */
  223.  
  224.       printf("\nEditing information for new user [%s]\n",uname);
  225.   
  226.       printf("\nFull Name: ",uname);
  227.       gets(person);
  228.       
  229.       printf("GID [%d]: ",DEFAULT_GROUP);
  230.       gets(foo);
  231.       group=atoi(foo);
  232.  
  233.       if (group==0)    /* You're not allowed to make root group users! */
  234.     group=DEFAULT_GROUP;
  235.  
  236.       unused_uid = find_unused(++unused_uid);    /* our k-eleet unused! */
  237.  
  238.       printf("\nUID [%d]: ",unused_uid);
  239.       gets(foo);
  240.       uid=atoi(foo);
  241.  
  242.       if(uid==0) /* this is how i detect if you just hit return. */
  243.         uid=unused_uid;
  244.                  /* it may also disable you from making a root user, but
  245.                   * doesen't that sound more like a feature?
  246.                   */
  247.  
  248.       if((pw=getpwuid(uid))!=NULL)    /* uhh. duhh. egh.. */
  249.       {
  250.         printf("\nWarning: UID [%d] is already in use, this would conflict with\n",uid);
  251.         printf("who is already owns that user ID. [%s]'s UID has been reset to\n",uname);
  252.         printf("the last unused UID: [%d].\n",unused_uid);
  253.         uid=unused_uid;
  254.       }
  255.       
  256.       fflush(stdin);
  257.       
  258.       printf("\nHome Directory [%s/%s]: ",DEFAULT_HOME,uname);
  259.       fflush(stdout);
  260.       gets(dir);
  261.  
  262.       if (!strcmp(dir,""))
  263.     sprintf(dir,"%s/%s",DEFAULT_HOME,uname);
  264.       fflush(stdin);
  265.  
  266.       printf("\nShell [%s]: ",DEFAULT_SHELL);
  267.       fflush(stdout);
  268.       gets(shell);
  269.       
  270.       if (!strcmp(shell,""))
  271.     sprintf(shell,"%s",DEFAULT_SHELL);
  272.       
  273.       printf("\nMin. Password Change Days [%d]: ",DEFAULT_MIN_PASS);
  274.       gets(foo);
  275.       min_pass = atoi(foo);
  276.       if (min_pass == 0)
  277.           min_pass = DEFAULT_MIN_PASS;
  278.             
  279.       printf("\nMax. Password Change Days [%d]: ",DEFAULT_MAX_PASS);
  280.       gets(foo);
  281.       if (strlen(foo) > 1)
  282.           max_pass = atoi(foo);
  283.       else
  284.           max_pass = DEFAULT_MAX_PASS;
  285.             
  286.       printf("\nPassword Warning Days [%d]: ",DEFAULT_WARN_PASS);
  287.       gets(foo);
  288.       warn_pass = atoi(foo);
  289.       if (warn_pass == 0)
  290.           warn_pass = DEFAULT_WARN_PASS;
  291.             
  292.       printf("\nDays after Password Expiry for Account Locking [%d]: ",DEFAULT_USER_DIE);
  293.       gets(foo);
  294.       user_die = atoi(foo);
  295.       if (user_die == 0)
  296.       user_die = DEFAULT_USER_DIE;
  297.       
  298.       while(!perfect) /* Sets up a loop until the password is entered correct twice */
  299.       {
  300.       
  301.       passwd = strd(getpass("Password: "));
  302.       if(strcmp(passwd,getpass("Retype Password: "))) {
  303.           fprintf(stderr, "Sorry, They do not match.\n");
  304.       perfect = 0;
  305.       }
  306.       else perfect = 1;
  307.       }    
  308.     
  309.       if (!strcmp(passwd,""))
  310.     sprintf(passwd,"%s",uname);
  311.       {
  312.     time(&tm);
  313.     salt[0] = (tm & 0x0f) +    'A';
  314.     salt[1] = ((tm & 0xf0) >> 4) + 'a';
  315.       }
  316.   
  317.       printf("\nInformation for new user [%s]:\n",uname);
  318.       printf("Home directory: [%s] Shell: [%s]\n",dir,shell);
  319.       printf("Password: [<hidden>] uid: [%d] gid: [%d]\n",uid,group);
  320.       printf("MinPass: [%d] MaxPass: [%d] WarnPass: [%d] UserExpire: [%d]\n",min_pass,max_pass,warn_pass,user_die);
  321.       printf("\nIs this correct? [y/N]: ");
  322.       fflush(stdout);
  323.       gets(foo);
  324.  
  325.       done=bad=correct=perfect=(foo[0]=='y'||foo[0]=='Y');
  326.  
  327.       if(bad!=1)
  328.        printf("\nUser [%s] not added\n",uname);
  329.     }
  330.  
  331.   /* Calculate days since Jan 1st, 1970 for pass_change_date */
  332.   
  333.   pass_change_date=(int)((time(NULL)/86400)-1);
  334.   
  335.   printf("\nAdding login [%s] and making directory [%s]\n",uname,dir);
  336.   mkdir(dir,DEFAULT_PERMS);
  337.  
  338.   system("cp /etc/passwd /etc/passwd.OLD"); /* Let's have safe sex */
  339.  
  340.   sprintf(tmp, "cp %s %s.OLD", SHADOW_FILE, SHADOW_FILE);
  341.   system(tmp);
  342.   
  343.   passwd_file=fopen(PASSWD_FILE,"a");
  344.  
  345.   shadow_file=fopen(SHADOW_FILE,"a");
  346.  
  347. #ifdef NO_CRYPT
  348.     
  349.     fprintf(passwd_file,"%s:x:%d:%d:%s:%s:%s\n"
  350.         ,uname,uid,group,person,dir,shell);
  351.     fprintf(shadow_file,"%s:%s:%d:%d:%d:%d:%d::\n", uname, fcrypt(passwd, salt), pass_change_date, min_pass, max_pass, warn_pass, user_die);
  352.  
  353. #else
  354.  
  355.     fprintf(passwd_file,"%s:x:%d:%d:%s:%s:%s\n"
  356.         ,uname,uid,group,person,dir,shell);
  357.     fprintf(shadow_file,"%s:%s:%d:%d:%d:%d:%d::\n", uname, crypt(passwd, salt), pass_change_date, min_pass, max_pass, warn_pass, user_die);
  358. #endif
  359.  
  360.   fflush(passwd_file);
  361.   fclose(passwd_file);
  362.  
  363.   fflush(shadow_file);
  364.   fclose(shadow_file);
  365.  
  366.   /* yes, I fixed uid and group being screwed around (chris) */
  367.  
  368.   /* make sure that they own their directory -- its kinda nice :) */
  369.   /* chown(dir,uid,group); */
  370.  
  371.   /* These are the Slackware hacks, added by Patrick Volkerding 12/3/93 */
  372.   /* ...and changed some more on Mon May 2 14:43:34 CDT 1994 */
  373.  
  374.   printf("\nAdding the files from the /etc/skel directory:\n"); 
  375.   fflush(stdout); 
  376.  
  377.   /* First, we "give" the /etc/skel directory to the new user: */
  378.  
  379.   sprintf(commandbuf,"chown --recursive %d.%d /etc/skel 2>/dev/null",uid,group);
  380.   system(commandbuf);
  381.  
  382.   /* Then, we copy the files owned by the new user into the new user's
  383.   home directory. This way, if there are already files in the user's home
  384.   directory (say, from a backup), the ownership of those files won't be 
  385.   changed. Some say this is progress. ;^) */
  386.  
  387.   sprintf(commandbuf,"( cd /etc/skel ; cp -a --verbose . %s )",dir); 
  388.   system(commandbuf); 
  389.  
  390.  /* It's useful to give the new home directory a current
  391.      creation date rather than the one from /etc/skel. */
  392.  
  393.   sprintf(commandbuf,"touch %s",dir); 
  394.   system(commandbuf); 
  395.  
  396.   /* Give this stuff back to root. By sure to put the uid/gid you want for
  397. the default ownership of /etc/skel into the line below if 0.0 isn't good.*/
  398.  
  399.   sprintf(commandbuf,"chown --recursive 0.0 /etc/skel 2> /dev/null"); 
  400.   system(commandbuf); 
  401.   sprintf(commandbuf,"touch /var/spool/mail/%s",uname); 
  402.   system(commandbuf); 
  403.   sprintf(commandbuf,"chown %d.mail /var/spool/mail/%s",uid,uname); 
  404.   system(commandbuf);
  405.   sprintf(commandbuf,"chmod 660 /var/spool/mail/%s",uname);
  406.   system(commandbuf); 
  407.   printf("\n\n"); 
  408.   fflush(stdout); 
  409.   /* End SlackHacks */
  410. }
  411. /* Here is our trade secret patented copyrighted code to find an unused UID */
  412.  
  413. find_unused(begin)
  414.     int begin;
  415. {
  416.     int trial;
  417.     struct passwd *pw;
  418.     trial = begin - 1;
  419.  
  420.         printf("\nChecking for an available UID after %d\n",FIRST);
  421.  
  422.     while ((pw = getpwuid(++trial)) != NULL) ;
  423.  
  424.     printf("\nFirst unused uid is %d\n", trial);
  425.  
  426.     return(trial);
  427. }
  428.  
  429.